package com.jinxixin.android.recordvideo;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import com.jinxixin.android.recordvideo.bean.MessageEvent;
import com.jinxixin.android.recordvideo.util.CameraHelp;
import com.jinxixin.android.recordvideo.util.MyVideoEditor;
import com.jinxixin.android.recordvideo.util.RecordUtil;
import com.jinxixin.android.recordvideo.util.RxJavaUtil;
import com.jinxixin.android.recordvideo.util.TimeUtils;
import com.jinxixin.android.recordvideo.widget.MySurfaceView;
import com.lansosdk.videoeditor.LanSoEditor;
import com.lansosdk.videoeditor.LanSongFileUtil;
import com.libyuv.LibyuvUtil;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.File;
import java.io.FileOutputStream;

/**
 * 拍照与拍视频activity
 */
public class RecordActivity extends AppCompatActivity {
    private LinearLayout ll_back;
    private ImageView img_take_picture;
    private ImageView img_switch_camera;

    private TextView tv_take_picture;
    private TextView tv_record_video;

    private final int MODE_PICTURE = 1;
    private final int MODE_VIDEO = 2;
    private int mMode = MODE_PICTURE;

    private LinearLayout ll_bottom;

    private MySurfaceView surfaceView;

    private Context mContext;

    private CameraHelp mCameraHelp = new CameraHelp();
    private SurfaceHolder mSurfaceHolder;

    private LinearLayout ll_stop_record_video;

    private ImageView img_stop_record_video;
    private TextView tv_time;

    public static void launch(Context context) {
        Intent intent = new Intent(context, RecordActivity.class);
        context.startActivity(intent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_record);
        mContext = this;

        LanSoEditor.initSDK(this, null);
        LanSongFileUtil.setFileDir("/sdcard/WeiXinRecorded/" + System.currentTimeMillis() + "/");
        LibyuvUtil.loadLibrary();

        initView();
        initData();
        initListener();
    }

    private void initView() {
        ll_back = findViewById(R.id.ll_back);
        tv_take_picture = findViewById(R.id.tv_take_picture);
        tv_record_video = findViewById(R.id.tv_record_video);

        img_take_picture = findViewById(R.id.img_take_picture);
        img_switch_camera = findViewById(R.id.img_switch_camera);

        surfaceView = findViewById(R.id.surfaceView);
        surfaceView.post(new Runnable() {
            @Override
            public void run() {
                int width = surfaceView.getWidth();
                int height = surfaceView.getHeight();
                float viewRatio = width * 1f / height;
                float videoRatio = 9f / 16f;
                ViewGroup.LayoutParams layoutParams = surfaceView.getLayoutParams();
                if (viewRatio > videoRatio) {
                    layoutParams.width = width;
                    layoutParams.height = (int) (width / viewRatio);
                } else {
                    layoutParams.width = (int) (height * viewRatio);
                    layoutParams.height = height;
                }
                surfaceView.setLayoutParams(layoutParams);
            }
        });

        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                mSurfaceHolder = holder;
                mCameraHelp.openCamera((Activity) mContext, mCameraHelp.getCameraId(), mSurfaceHolder);
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                mCameraHelp.release();
            }
        });

        surfaceView.setOnSlidingEventsListener(new MySurfaceView.OnSlidingEventsListener() {
            @Override
            public void leftMove() {
                tv_record_video.performClick();
            }

            @Override
            public void rightMove() {
               tv_take_picture.performClick();
            }
        });

        mCameraHelp.setPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                if (mIsShotPhoto) {
                    mIsShotPhoto = false;
                    shotPhoto(data);
                } else if (mIsRecordVideo) {
                    if (mOnPreviewFrameListener != null) {
                        mOnPreviewFrameListener.onPreviewFrame(data);
                    }
                }
            }
        });

        ll_stop_record_video = findViewById(R.id.ll_stop_record_video);
        img_stop_record_video = findViewById(R.id.img_stop_record_video);
        tv_time = findViewById(R.id.tv_time);
        ll_stop_record_video.setVisibility(View.GONE);

        ll_bottom = findViewById(R.id.ll_bottom);
    }

    private void initData() {

    }

    private void initListener() {
        ll_back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        img_stop_record_video.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mIsRecordVideo = false;
                stopRecord();
            }
        });

        tv_take_picture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mMode = MODE_PICTURE;
                tv_take_picture.setTextColor(ContextCompat.getColor(mContext, R.color.color_ffc028));
                tv_record_video.setTextColor(ContextCompat.getColor(mContext, R.color.white));
                img_take_picture.setImageResource(R.drawable.ic_take_picture);
            }
        });

        tv_record_video.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mMode = MODE_VIDEO;
                tv_take_picture.setTextColor(ContextCompat.getColor(mContext, R.color.white));
                tv_record_video.setTextColor(ContextCompat.getColor(mContext, R.color.color_ffc028));
                img_take_picture.setImageResource(R.drawable.ic_record_video);
            }
        });

        surfaceView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mCameraHelp.callFocusMode();
            }
        });

        img_take_picture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mMode == MODE_PICTURE) {
                    mIsShotPhoto = true;
                } else {
                    mIsRecordVideo = true;
                    startRecord();
                }
            }
        });

        img_switch_camera.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mCameraHelp.getCameraId() == Camera.CameraInfo.CAMERA_FACING_BACK) {
                    mCameraHelp.openCamera((Activity)mContext, Camera.CameraInfo.CAMERA_FACING_FRONT, mSurfaceHolder);
                } else {
                    mCameraHelp.openCamera((Activity)mContext, Camera.CameraInfo.CAMERA_FACING_BACK, mSurfaceHolder);
                }
            }
        });
    }


    @Override
    protected void onResume() {
        super.onResume();
        initRecorderState();
    }

    /**
     * 初始化视频拍摄状态
     */
    private void initRecorderState() {
        ll_bottom.setVisibility(View.VISIBLE);
        ll_stop_record_video.setVisibility(View.GONE);
        tv_time.setText("00:00:00");
    }

    private long videoDuration;
    private long recordTime;
    private String videoPath;
    private String audioPath;
    private RecordUtil recordUtil;
    private RecordUtil.OnPreviewFrameListener mOnPreviewFrameListener;

    private void startRecord() {
        ll_bottom.setVisibility(View.GONE);
        ll_stop_record_video.setVisibility(View.VISIBLE);

        RxJavaUtil.run(new RxJavaUtil.OnRxAndroidListener<Boolean>() {
            @Override
            public Boolean doInBackground() throws Throwable {
                videoPath = LanSongFileUtil.DEFAULT_DIR + System.currentTimeMillis() + ".h264";
                audioPath = LanSongFileUtil.DEFAULT_DIR + System.currentTimeMillis() + ".pcm";
                final boolean isFrontCamera = mCameraHelp.getCameraId() == Camera.CameraInfo.CAMERA_FACING_FRONT;
                final int rotation;
                if (isFrontCamera) {
                    rotation = 270;
                } else {
                    rotation = 90;
                }
                recordUtil = new RecordUtil(videoPath, audioPath, mCameraHelp.getWidth(), mCameraHelp.getHeight(), rotation, isFrontCamera);
                return true;
            }

            @Override
            public void onFinish(Boolean result) {
                mOnPreviewFrameListener = recordUtil.start();
                videoDuration = 0;
                recordTime = System.currentTimeMillis();
                runLoopPro();
            }

            @Override
            public void onError(Throwable e) {

            }
        });
    }

    public static final float MAX_VIDEO_TIME = 60 * 60 * 1000f;  //最大录制时间为1小时
    //public static final float MAX_VIDEO_TIME = 10 * 1000f;  //最大录制时间为10秒

    private void runLoopPro() {

        RxJavaUtil.loop(20, new RxJavaUtil.OnRxLoopListener() {
            @Override
            public Boolean takeWhile() {
                return recordUtil != null && recordUtil.isRecording();
            }

            @Override
            public void onExecute() {
                long currentTime = System.currentTimeMillis();
                videoDuration += currentTime - recordTime;
                recordTime = currentTime;
                final long countTime = videoDuration;
                if (countTime <= MAX_VIDEO_TIME) {
                    tv_time.setText(TimeUtils.formatLongToTimeStr(countTime));
                } else {
                    if(recordUtil != null && recordUtil.isRecording()){
                        recordUtil.stop();
                        tv_time.setText(TimeUtils.formatLongToTimeStr(countTime));
                        Toast.makeText(mContext, "已达最大录制时长", Toast.LENGTH_LONG).show();
                        img_stop_record_video.performClick();
                    }
                }
            }

            @Override
            public void onFinish() {

            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }
        });
    }

    private MyVideoEditor mVideoEditor = new MyVideoEditor();

    private void stopRecord() {
        if (recordUtil != null) {
            recordUtil.stop();
            recordUtil.release();
            recordUtil = null;
        }
        RxJavaUtil.run(new RxJavaUtil.OnRxAndroidListener<String>() {
            @Override
            public String doInBackground() throws Exception {
                //h264转mp4
                String mp4Path = LanSongFileUtil.DEFAULT_DIR + System.currentTimeMillis() + ".mp4";
                mVideoEditor.h264ToMp4(videoPath, mp4Path);
                //合成音频
                String aacPath = mVideoEditor.executePcmEncodeAac(audioPath, RecordUtil.sampleRateInHz, RecordUtil.channelCount);
                //音视频混合
                mp4Path = mVideoEditor.executeVideoMergeAudio(mp4Path, aacPath);
                return mp4Path;
            }

            @Override
            public void onFinish(String result) {
                //closeProgressDialog();
                RecordVideoFinishActivity.launch(mContext, result);
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
                //closeProgressDialog();
            }
        });
    }

    private boolean mIsShotPhoto = false;//是否是拍照
    private boolean mIsRecordVideo = false;//是否是录屏

    private void shotPhoto(final byte[] data) {
        RxJavaUtil.run(new RxJavaUtil.OnRxAndroidListener<String>() {
            @Override
            public String doInBackground() throws Throwable {
                boolean isFrontCamera = mCameraHelp.getCameraId() == Camera.CameraInfo.CAMERA_FACING_FRONT;
                int rotation;
                if (isFrontCamera) {
                    rotation = 270;
                } else {
                    rotation = 90;
                }

                byte[] yuvI420 = new byte[data.length];
                byte[] tempYuvI420 = new byte[data.length];

                int videoWidth = mCameraHelp.getHeight();
                int videoHeight = mCameraHelp.getWidth();

                LibyuvUtil.convertNV21ToI420(data, yuvI420, mCameraHelp.getWidth(), mCameraHelp.getHeight());
                LibyuvUtil.compressI420(yuvI420, mCameraHelp.getWidth(), mCameraHelp.getHeight(), tempYuvI420,
                        mCameraHelp.getWidth(), mCameraHelp.getHeight(), rotation, isFrontCamera);

                Bitmap bitmap = Bitmap.createBitmap(videoWidth, videoHeight, Bitmap.Config.ARGB_8888);

                LibyuvUtil.convertI420ToBitmap(tempYuvI420, bitmap, videoWidth, videoHeight);

                String filePath = LanSongFileUtil.DEFAULT_DIR + System.currentTimeMillis() + ".jpg";
                File file = new File(filePath);
                try {
                    FileOutputStream fos = new FileOutputStream(file);
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                    fos.flush();
                    fos.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return filePath;
            }

            @Override
            public void onFinish(String result) {
                TakePictureFinishActivity.launch(mContext, result);
            }

            @Override
            public void onError(Throwable e) {

            }
        });
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {
        if (event.getMsgCode() == MessageEvent.FINISH_RECORD_VIDEO) {
            finish();
        } else if (event.getMsgCode() == MessageEvent.FINISH_TAKE_PICTURE) {
            finish();
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        //注册EventBus
        if (!EventBus.getDefault().isRegistered(this)) {//加上判断
            EventBus.getDefault().register(this);
        }
    }

    @Override
    protected void onDestroy() {
        if (mCameraHelp != null) {
            mCameraHelp.release();
        }
        if (recordUtil != null) {
            recordUtil.stop();
        }
        //取消注册EventBus
        if (EventBus.getDefault().isRegistered(this)) {//加上判断
            EventBus.getDefault().unregister(this);
        }
        super.onDestroy();
    }
}
